package pl.pyjter;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Vector;
import javax.persistence.Column;
import javax.swing.table.AbstractTableModel;

public class HibernateTableModel<T> extends AbstractTableModel {

	private Vector<String> columns;
	private Vector<Method> methods;
	private LinkedHashMap<Class, Method> joinedClassesMap;
	private LinkedHashMap<Class, LinkedHashMap<String, Method>> joinedClassesElements;
	private Vector<Vector<Object>> data;
	
	public HibernateTableModel(Class<T> cls) throws Throwable {
		
		columns = new Vector<String>();
		methods = new Vector<Method>();
		joinedClassesMap = new LinkedHashMap<Class, Method>();
		joinedClassesElements = new LinkedHashMap<>();
		data = new Vector<>();
		
		columns.addAll(LibraryHibImpl.getElements(cls).keySet());
		methods.addAll(LibraryHibImpl.getElements(cls).values());
		
		joinedClassesMap.putAll(LibraryHibImpl.getJoindedClasses(cls));
		
		for(Class joinedClass : joinedClassesMap.keySet()) {
//			columns.addAll(LibraryHibImpl.getElements(joinedClass).keySet());
			LinkedHashMap<String, Method> tempElementsMap = new LinkedHashMap<>();
			tempElementsMap.putAll(LibraryHibImpl.getElements(joinedClass));
			tempElementsMap.remove("id");
			joinedClassesElements.put(joinedClass, tempElementsMap);
			columns.addAll(joinedClassesElements.get(joinedClass).keySet());
		}
	}
	
	private Vector<Object> prepareRow(T object) throws Throwable {
		Vector<Object> row = new Vector<>();
		
		for(Method method : methods) {
			row.add(method.invoke(object));
		}
		
		for(Class joinedClass : joinedClassesMap.keySet()) {		
			Object joinedObject = joinedClassesMap.get(joinedClass).invoke(object);
			
			for(Method joinedClassMethod : joinedClassesElements.get(joinedClass).values()) {
//			for(Method joinedClassMethod : (Collection<Method>) LibraryHibImpl.getElements(joinedClass).values()) {		
				row.add(joinedClassMethod.invoke(joinedObject));
			}
		}
		
		return row;
	}
	
	public void insertRow(T object) throws Throwable {
		data.add(prepareRow(object));
	}
	
	public void updateRow(int index, T object) throws Throwable {
		data.set(index, prepareRow(object));
	}
	
	public void deleteRow(int index) {
		data.remove(index);
	}
	
	@Override
	public int getColumnCount() {
		return columns.size();
	}
	
	@Override
	public String getColumnName(int i) {
		return columns.get(i);
	}

	@Override
	public int getRowCount() {
		return data.size();
	}

	@Override
	public Object getValueAt(int nRow, int nCol) {
		return data.get(nRow).get(nCol);
	}

}
